//
// Created by gogoqiu on 2022/1/11.
//

#include "wx/wx.h"
#include "wx/confbase.h"
#include "wx/stdpaths.h"
#include "wx/sysopt.h"
#include <wx/fs_zip.h> // ZIP filesystem support
#include <wx/tipdlg.h>
#include <wx/cshelp.h>
#include <wx/image.h>
//#include "libssh2.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include "action_event.h"
#include "view/PreferenceAdapter.h"
#include <arpa/inet.h>
#include "scp/scp.h"
#include "sql/sql.h"
#include "func.h"
#include "MainDialog.h"

#define MY_SQL_HOST "git.my.host"
#define MY_SQL_USER "gogoqiu"
#define MY_SQL_PASS "512512ZoPoqiu"
#define MY_SQL_DB "repository"
#define MY_SQL_PORT 3306

using namespace std;

//
class DelayThread: public wxThread
{
    wxWindow * parent;
public:
    DelayThread ( wxWindow * parent )
    {
        this->parent = parent;
    }
    void * Entry() override
    {
        while ( true ) {
            sleep ( 1 );
            ActionEvent event ( this->parent, Delay_TEST );
            event.Post();
        }
    }
};

class PostFileWorker: public wxThread
{
    //friend class MainDialog;
    MainDialog* dialog;
public:
    PostFileWorker ( MainDialog* dialog )
    {
        this->dialog = dialog;
    }
    void * Entry() override
    {
        dialog->post();
    }
};

//
BEGIN_EVENT_TABLE ( MainDialog, wxFrame )
                EVT_MENU ( ACTION_EVENT, MainDialog::OnActionEvent )
                EVT_BUTTON ( ID_BUTTON_DELAY, MainDialog::OnRunDelay )
                EVT_BUTTON ( ID_BUTTON_START_POST, MainDialog::OnStartPost )
                EVT_FILEPICKER_CHANGED( ID_FILE_PICKER, MainDialog::OnFilePickerChange )
END_EVENT_TABLE()


//如何去掉
//动态添加配置?
/**
 * wxDEFAULT_FRAME_STYLE
 * wxDEFAULT_FRAME_STYLE ^ wxMAXIMIZE_BOX ^ wxRESIZE_BORDER
 *
 * @param _myTagApp
 */
MainDialog::MainDialog ( wxWindow *parent, MyTagApp * _myTagApp )
        : wxFrame ( parent, wxID_ANY, "配置", wxDefaultPosition, wxDefaultSize,
                    wxDEFAULT_FRAME_STYLE ^ wxMAXIMIZE_BOX ^ wxRESIZE_BORDER )
{
    this->myTagApp = _myTagApp;
    auto *menuFile = new wxMenu;
    //
    menuFile->Append ( ID_Hello, "&Hello...\tCtrl-H",
                       "Help string shown in status bar for this menu item" );
    menuFile->AppendSeparator();
    menuFile->Append ( wxID_EXIT );
    auto *menuHelp = new wxMenu;
    menuHelp->Append ( wxID_ABOUT );
    auto *menuBar = new wxMenuBar;
    menuBar->Append ( menuFile, "&File" );
    menuBar->Append ( menuHelp, "&Help" );
    SetMenuBar ( menuBar );
    CreateStatusBar();
    //SetStatusText ( "Welcome to wxWidgets!" );
    //
    Bind ( wxEVT_MENU, &MainDialog::OnHello, this, ID_Hello );
    Bind ( wxEVT_MENU, &MainDialog::OnAbout, this, wxID_ABOUT );
    Bind ( wxEVT_MENU, &MainDialog::OnExit, this, wxID_EXIT );
    //Bind( EVT_FILEPICKER_CHANGED, )
    SetClientSize ( wxSize ( 350, 500 ) );
    //
    dialogRootBoxSizer = new wxBoxSizer ( wxVERTICAL );
    m_listbox = new wxScrolledWindow ( this, wxID_ANY,
                                       wxDefaultPosition, wxDefaultSize, wxHSCROLL | wxVSCROLL );
    //m_listbox: panelRootBoxSizer
    //panels: innerSizer
    m_listbox->SetScrollRate ( 5, 5 );
    //
    dialogRootBoxSizer->Add ( m_listbox, 1, wxEXPAND, 0 );
    this->SetSizer ( dialogRootBoxSizer );
    //m_listbox->SetBackgroundColour(wxColour(0, 128, 192 ) );
    //return;
    //wxBoxSizer *BoxSizer = new wxBoxSizer(wxHORIZONTAL);
    //panelRootBoxSizer = new wxBoxSizer(wxVERTICAL);

    //
    //BuildView();

    mPreferenceAdapter = new PreferenceAdapter ( myTagApp, this, m_listbox );

    //connect this::close to this::dismiss
    //https://blog.csdn.net/sq8706/article/details/119087505
    //wxWidgets 关闭按钮
    //动态设置的
    Bind ( wxEVT_CLOSE_WINDOW, wxCloseEventHandler ( MainDialog::OnClose ), this );
    //bind the request data to the this frame on the data
    //PreferenceAdapter::OnActionEvent ( wxCommandEvent & event )
    /*
     * void Bind(const EventTag &eventType,
              void (Class::*method)(EventArg &),
              EventHandler *handler,
              int winid = wxID_ANY,
    EVT_MENU ( ACTION_EVENT, MainFrame::OnActionEvent )
     */
    //Bind( ACTION_EVENT, wxCommandEventHandler(PreferencesFrame::OnActionEvent ), this );
    request();
}

void MainDialog::buildMenu()
{
    auto *menuFile = new wxMenu;
    //
    menuFile->Append ( ID_Hello, "&Hello...\tCtrl-H",
                       "Help string shown in status bar for this menu item" );
    menuFile->AppendSeparator();
    menuFile->Append ( wxID_EXIT );

    auto *menuHelp = new wxMenu;
    menuHelp->Append ( wxID_ABOUT );

    auto *menuBar = new wxMenuBar;
    menuBar->Append ( menuFile, "&File" );
    menuBar->Append ( menuHelp, "&Help" );
    SetMenuBar ( menuBar );

    //
    Bind ( wxEVT_MENU, &MainDialog::OnHello, this, ID_Hello );
    Bind ( wxEVT_MENU, &MainDialog::OnAbout, this, wxID_ABOUT );
    Bind ( wxEVT_MENU, &MainDialog::OnExit, this, wxID_EXIT );
}

//
MainDialog::MainDialog ( MyTagApp *_myTagApp, const wxString &title, const wxLocale &locale )
        : wxFrame ( NULL, wxID_ANY, "配置", wxDefaultPosition, wxDefaultSize,
                    wxDEFAULT_FRAME_STYLE ^ wxMAXIMIZE_BOX ^ wxRESIZE_BORDER )
{
    this->myTagApp = _myTagApp;

    CreateStatusBar();
    //SetStatusText ( "Welcome to wxWidgets!" );
    //
    SetClientSize ( wxSize ( 350, 500 ) );
    //
    dialogRootBoxSizer = new wxBoxSizer ( wxVERTICAL );
    //
    //m_listbox = new wxScrolledWindow(this, wxID_ANY,
    //								 wxDefaultPosition, wxDefaultSize, wxHSCROLL | wxVSCROLL );
    //m_listbox: panelRootBoxSizer
    //panels: innerSizer
    //m_listbox->SetScrollRate(5, 5 );
    //
    //dialogRootBoxSizer->Add(m_listbox, 1, wxEXPAND, 0 );

    m_gauge1 = new wxGauge( this, wxID_ANY, 101, wxDefaultPosition, wxDefaultSize, wxGA_HORIZONTAL );
    m_gauge1->SetValue( 0 );

    dialogRootBoxSizer->Add( m_gauge1, 0, wxALL | wxEXPAND, 5 );

    //test_delay_button = new wxButton( this, ID_BUTTON_DELAY, "Delay");
    //dialogRootBoxSizer->Add( test_delay_button, 0, wxALL, 5 );

    m_filePicker1 = new wxFilePickerCtrl ( this, ID_FILE_PICKER, wxEmptyString, wxT ( "Select a file" ), wxT ( "*.*" ),
                                           wxDefaultPosition, wxDefaultSize, wxFLP_DEFAULT_STYLE );
    dialogRootBoxSizer->Add ( m_filePicker1, 0, wxALL | wxEXPAND, 5 );

    start_post_button = new wxButton ( this, ID_BUTTON_START_POST, "启动传送" );
    dialogRootBoxSizer->Add ( start_post_button, 0, wxALL, 5 );

    wxSize size ( 300, 500 );
    m_logBox = new wxTextCtrl ( this, wxID_ANY, wxEmptyString, wxDefaultPosition, size, wxTE_MULTILINE );
    dialogRootBoxSizer->Add ( m_logBox,  0, wxALL | wxEXPAND, 5  );

    this->SetSizer ( dialogRootBoxSizer );
    mPreferenceAdapter = new PreferenceAdapter ( myTagApp, this, m_listbox );

    //form
    //path, button_start( pause ), log
    //选择文件
    //拖拽

    //Bind(wxEVT_CLOSE_WINDOW,wxCloseEventHandler(MainDialog::OnClose),this);
    conn_ptr = mysql_init(nullptr);
    if (!conn_ptr) {
        //0
        //printf("mysql_init failed\n");
        //fail
        addLog("mysql初始化失败");
    }
    conn_ptr = mysql_real_connect( conn_ptr, MY_SQL_HOST, MY_SQL_USER, MY_SQL_PASS,
                                  MY_SQL_DB, MY_SQL_PORT, nullptr, 0);
    if (!conn_ptr) {
        addLog("mysql连接失败");
    }else
        addLog("mysql已连接");
    item = 0;
}

/*
 * background service
 * onInit的时候启动，关闭时关闭。ui上可以看见状态
 */
void MainDialog::request()
{
    vector< PreferenceView*> items = myTagApp->getPreferenceCore()->getPreferenceViews();
    mPreferenceAdapter->setItemsWithNotify ( items );
    //this->SetSizer(dialogRootBoxSizer);
    //Layout();
}

void MainDialog::OnClose ( wxCloseEvent&  event )
{
    this->Show ( false );
}

MainDialog::~MainDialog()
{
    for ( int i = 0; i < panels.size(); i++ ) {
        //panels.at(i)->Disconnect( wxEVT_LEFT_DOWN, wxMouseEventHandler( PreferencesFrame::OnClickItem ), NULL, this );
    }
    //this->delayThread.
    //stop the thread
    //release the thread
    //if ( delayThread->IsRunning() ) {
        //delayThread->Kill();
        //delayThread->Delete();
    //}
    //delete delayThread;
    if( this->item )
        delete item;
    if( conn_ptr )
        mysql_close(conn_ptr);
}

void MainDialog::OnExit ( wxCommandEvent& event )
{
    Close ( true );
}

void MainDialog::OnAbout ( wxCommandEvent& event )
{
    wxMessageBox ( "This is a wxWidgets Hello World example",
                   "About Hello World", wxOK | wxICON_INFORMATION );
}

void MainDialog::OnHello ( wxCommandEvent& event )
{
    wxLogMessage ( "Hello world from wxWidgets!" );
}

void MainDialog::OnClickItem ( wxMouseEvent &event )
{

}

void MainDialog::OnActionEvent ( wxCommandEvent &event )
{
    const int token = event.GetInt();
    const long liType = event.GetExtraLong();
    switch ( token ) {
        case TOKEN_INFO:
            break;
        case TOKEN_ERROR:
            break;
        case TOKEN_ACTION_START:
            break;
        case TOKEN_ACTION_END:
            break;
        case Delay_TEST: {
            int value = m_gauge1->GetValue();
            m_gauge1->SetValue(value + 1);
            break;
        }
        case TOKEN_LOG:{
            wxString log = event.GetString();
            addLog( log );
            break;
        }
        case TOKEN_SCP_PERCENT:{
            auto *value = (int*)event.GetClientData();
            printf( "%d\n", *value );
            m_gauge1->SetValue(*value);
            delete value;
            break;
        }
    }
}

//
void MainDialog::startService()
{
    this->start_post_button->Disable();
    postFileWorker = new PostFileWorker ( this );
    postFileWorker->Run();
}

//service thread

//post file thread
void MainDialog::post()
{
//    this->m_gauge1->SetValue( 50 );
    //运行在非ui线程里，非ui线程直接控制ui?
    if ( scp() == 0 ) {
        addEventLog( this->item->path );
        addEventLog("文件信息已上传");
        if ( record() == 0 ) {
            //文件信息到日志
            //清空file pick
            //this->start_post_button->Enable();
            //
            addEventLog("文件信息已记录");
        } else {
            addEventLog("record fail...");
        }
    } else {
        //add log
        //post log
        //log control, 定向消息
        //post percent
        addEventLog("scp fail...");
    }
}

//how to set the handle rule to the message destination
//wxWindow *parent
//if the parent get the event( message )
//BEGIN_EVENT_TABLE ( MainFrame, wxFrame )
//				EVT_MENU ( ID_AddWcBookmark, MainFrame::OnAddWcBookmark )
//void MainFrame::OnActionEvent ( wxCommandEvent & event )
//case TOKEN_ACTION_START:
//EVT_MENU ( ACTION_EVENT, MainFrame::OnActionEvent )
int MainDialog::scp(){
    char md5sum[255] = {0};
    if( scpRep( this, item->path, item->uuid, md5sum ) ){
        addEventLog( "拷贝出错" );
        return -1;
    };
    this->item->md5 = md5sum;
    return 0;
}

/*
void postMsg( wxWindow *parent ){
	ActionEvent event( parent, PostFile_SCP_START, LogItem_Normal, _("Execute:"), "");

	event.Post();
}
 */

//
int MainDialog::record()
{
    const char* _sql;
    wxString sql = buildSql();
    _sql = sql.mb_str(wxConvUTF8);
    int retVal;
    if ( _sql != nullptr && conn_ptr!= nullptr ) {
        retVal = mysql_query(conn_ptr, "SET NAMES UTF8");
        retVal = mysql_query(conn_ptr, _sql);
        if (retVal != 0) {
            addEventLog( mysql_error(conn_ptr) );
            addEventLog( sql );
            return -1;
        }
    }
    return 0;
}

//服务线程，每隔一秒发送一次消息
void MainDialog::OnRunDelay ( wxCommandEvent& event )
{
    delayThread = new DelayThread ( this );
    delayThread->Run();
    test_delay_button->Disable();

}

void MainDialog::OnStartPost(wxCommandEvent &event) {
    wxString path = this->m_filePicker1->GetPath();
    if( path.IsSameAs(_T("")))
        return;
    this->item = new Item();
    //memset( item, sizeof( Item ), 1 );
    this->item->path = path;
    this->item->name = this->m_filePicker1->GetFileName().GetFullName();
    this->item->size = this->m_filePicker1->GetFileName().GetSize().GetValue();
    this->item->lastModified = this->m_filePicker1->GetFileName().GetModificationTime().GetValue().GetValue();
    this->item->uuid = gen_uuid_string();

    startService();
}

void MainDialog::addEventLog( const wxString& log ){
    wxString tmp = log;
    if( !log.EndsWith("\n"))
        tmp = tmp +  _T("\n") ;
    ActionEvent event( this, TOKEN_LOG, tmp );
    event.Post();
}

void MainDialog::addLog( const wxString& log ){
    wxString tmp = log;
    if( !log.EndsWith("\n"))
        tmp = tmp +  _T("\n") ;
    this->m_logBox->AppendText( tmp );
}

wxString MainDialog::buildSql (  )
{
    wxString sql;
    sql.sprintf ( _T( "INSERT INTO `repository` ( `uuid`, `name`, `size`, `md5`, `lastmodified`, `mime`, `path`, `accessType`, `filetype`, `recordtime`, `content`, `tags`) VALUES( '%s', '%s', %lld, '%s', %lld, '%s', '%s', %d, %d, NOW(), '%s', '%s' );"),
              item->uuid, item->name, item->size, item->md5, item->lastModified,
              item->mime, item->path, item->accessType, item->fileType, item->content, item->tags );
    //printf ( "%s\n", sql );
    return sql;
}

void MainDialog::OnFilePickerChange(wxFileDirPickerEvent &event) {
    this->start_post_button->Enable();
}
